package uk.co.q3c.deplan.client.service;

import java.util.List;
import java.util.concurrent.TimeoutException;

import org.apache.log4j.Logger;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import uk.co.q3c.deplan.client.Orchestrator;
import uk.co.q3c.deplan.client.domain.dag.DAG;
import uk.co.q3c.deplan.client.domain.resource.PersistenceReferenceException;
import uk.co.q3c.deplan.client.domain.task.Task;
import uk.co.q3c.deplan.client.domain.task.BaseTask;
import uk.co.q3c.deplan.client.domain.task.Task;
import uk.co.q3c.deplan.client.ui.mock.service.TaskRPCMock;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.googlecode.objectify.Key;

@Test
public class TaskServiceClient_UT {
	private static final long TIMEOUT_MILLIS = 100;
	private TaskServiceClient tsc;
	transient protected final Logger logger = Logger.getLogger(getClass().getName());

	boolean testDone = false;
	int integerResult;
	List<? extends Task> taskListResult;

	public class IntegerCallback implements AsyncCallback<Integer> {
		@Override
		public void onFailure(Throwable caught) {
			logger.debug("failure from integer callback");
			setTestDone(true);
		}

		@Override
		public void onSuccess(Integer result) {
			logger.debug("Success from integer callback with value = " + result.toString());
			integerResult = result;
			setTestDone(true);
		}

	}

	public class TaskListCallback implements AsyncCallback<List<? extends Task>> {

		@Override
		public void onFailure(Throwable caught) {
			logger.debug("failure from task list callback");
			setTestDone(true);
		}

		@Override
		public void onSuccess(List<? extends Task> result) {
			logger.debug("Success from task list callback with value = " + result.toString());
			taskListResult = result;
			setTestDone(true);
		}

	}

	@BeforeMethod
	protected void beforeMethod() {
		tsc = new TaskServiceClient();
		tsc.setRpc(new TaskRPCMock(10));
		setTestDone(false);
		integerResult = 0;
		taskListResult = null;
	}

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TESTS START ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	public void countPlanManagers() throws InterruptedException, TimeoutException {
		tsc.countPlanManagers(new IntegerCallback());
		waitForResult();
		Assert.assertEquals(integerResult, 7);
	}

	/**
	 * target has no predecessors, Dag is already in cache
	 * 
	 * @throws TimeoutException
	 * @throws PersistenceReferenceException
	 */
	public void predecessorsForNoneDagPresent() throws TimeoutException, PersistenceReferenceException {
		BaseTask pt = new BaseTask(null);
		tsc.save(pt);
		DAG<Key<Task>> dependencies = new DAG<Key<Task>>();
		dependencies.setKeyId(1L);
		Orchestrator.getCache()
				.add(dependencies);
		tsc.predecessorsFor(pt, new TaskListCallback());
		waitForResult();
		Assert.assertNotNull(taskListResult);
		Assert.assertEquals(taskListResult.size(), 0);
	}

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TESTS END ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	synchronized private boolean isTestDone() {
		return testDone;
	}

	synchronized private void setTestDone(boolean testDone) {
		this.testDone = testDone;
	}

	private void waitForResult() throws TimeoutException {
		long end = System.currentTimeMillis() + TIMEOUT_MILLIS;
		while ((System.currentTimeMillis() < end) && (!isTestDone())) {
			// wait
		}
		if (isTestDone()) {
			return;
		}
		throw new TimeoutException();
	}
}
